﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;

namespace Skybot.Base
{
    using Skybot.Extension;
    using Skybot.Logs;
    using Skybot.Base.Pool;
    /// <summary>
    /// OTM,OTA协议终端上传数据日志记录
    /// 最后修改日期:2015-07-22
    /// </summary>
    public class TerminalMessageRecordOtmOTA
    {
        private readonly static TerminalMessageRecordOtmOTA _instance = new TerminalMessageRecordOtmOTA();
        /// <summary>
        /// 终端上传数据日志记录
        /// </summary>
        /// <returns>返回单例对像</returns>
        public static TerminalMessageRecordOtmOTA Create()
        {
            return _instance;
        }



        /// <summary>
        /// 开始时间
        /// </summary>
        internal DateTime startTime = DateTime.Now.AddMonths(1);



        /// <summary>
        /// 创建一个新的 终端上传数据日志记录 对像 
        /// </summary>
        public TerminalMessageRecordOtmOTA()
        {
            IsWorking = true;
            //初始5个线程
            System.Linq.Enumerable.Range(0, 5).ToList().ForEach((index) =>
                                                                    {
                                                                        //创建写入数据对像
                                                                        RecordBufferCreate(index);
                                                                    });

        }


        #region 多写入线程
        //初始化4线程
        internal System.Collections.Concurrent.ConcurrentDictionary<int, BuffRecordTask<BuffRecord>> taskDic = new System.Collections.Concurrent.ConcurrentDictionary<int, BuffRecordTask<BuffRecord>>(4, 4);

        /// <summary>
        /// 创建一个用于写入的数据对像
        /// </summary>
        /// <param name="syncPoint">数据节点</param>
        /// <param name="index">对应的索引</param>
        /// <returns></returns>
        protected BuffRecordTask<BuffRecord> RecordBufferCreate(int index)
        {
            BuffRecordTask<BuffRecord> buf = null;
            lock (taskDic)
            {
                buf = new BuffRecordTask<BuffRecord>()
                {
                    TagName = index.ToString(),
                    Splict = index,
                };
                buf.Task = new TaskEx(CycleWrite, buf, new System.Threading.CancellationTokenSource()){ AutoReRun=true, StartTime=DateTime.Now, ThreadName="OTM终端上报OTA协议日志记录线程"};
                if (taskDic.TryAdd(index, buf))
                {
                    //开始发送线程
                    buf.Task.Start();
                    ThreadManager.Instance.Add(buf.Task);
                }
            }

            return buf;
        }

        /// <summary>
        /// 写日志处理数据对像实例
        /// </summary>
        protected WriteLog2 writeLog = new WriteLog2();

        #endregion


        /// <summary>
        /// 当前队列的工作状态
        /// </summary>
        public bool IsWorking { get; set; }

        /// <summary>
        /// 将当前获取的buff存放到写入队列当中
        /// </summary>
        /// <param name="message">收到的协义数据</param>
        public void Push(byte[] message)
        {
            var pop = pool.Pop();
            //数据长度
            pop.Length = message.Length;
            //将数据复制到池
            Buffer.BlockCopy(message, 0, pop.Bytes, 0, message.Length);
 
            //用于写入的线程对像
            string vinno = System.Text.Encoding.ASCII.GetString(pop.Bytes, 7, 17);
            //终端号
            uint terminalcode = (uint)Math.Abs(vinno.GetHashCode());
            //跟据终端号分配线程
            int index = (int)(terminalcode % taskDic.Count);
            //每一个节点一个线程
            BuffRecordTask<BuffRecord> recordWrite = taskDic[index];
            //添加数据
            lock (recordWrite.Queuedata)
            {
                recordWrite.Queuedata.Enqueue(pop);
            }
            #region 性能记数
            //添加总个数
            System.Threading.Interlocked.Increment(ref  pushCount);

            #endregion
        }



        private void CycleWrite(object o)
        {
            BuffRecordTask<BuffRecord> task = (BuffRecordTask<BuffRecord>)o;

            while (IsWorking)
            {
                CycleWriteDetail(task.Queuedata);

            }
        }

        private void CycleWriteDetail(Queue<BuffRecord> queue)
        {
            //记时
            if (startTime > DateTime.Now)
            {
                startTime = DateTime.Now;
            }

            try
            {
                BuffRecord pop = null;
                lock (queue)
                {
                    if (queue.Count > 0)
                    {
                        pop = queue.Dequeue();
                    }
                }

                if (pop == null)
                {
                    Thread.Sleep(2);
                    return;
                }
                int index = 5;
                //OTMOTA数据协议
                string vinno = System.Text.Encoding.ASCII.GetString(pop.Bytes, 7, 17).Replace("\0",string.Empty);
                int seq = pop.Bytes.ReadUshort(ref index);
                int cmd = pop.Bytes[1];
                 
                writeLog.Write(vinno, string.Format("c:{0},seq{1} {2}",cmd.ToString("X2"), seq.ToString("d6"), BitConverter.ToString(pop.Bytes, 0, pop.Length).Replace("-", string.Empty)));

                //还池
                pool.GaveBack(pop);

              
 
                #region 性能记数
                //将记数器加1
                System.Threading.Interlocked.Increment(ref  processingCount);

                #endregion

            }
            catch (Exception ex)
            {

                LogProvider.Create().Write(EventType.Error, ex);
            }
        }




        #region 池
        /// <summary>
        /// 写数据池
        /// </summary>
        internal TerminalMessageRecordPool pool = new TerminalMessageRecordPool();

        #endregion

        #region 性能记数与统计信息

        /// <summary>
        /// 1.添加总个数
        /// </summary>
        long pushCount;
 

        /// <summary>
        /// 处理总个数
        /// </summary>
        internal long processingCount = 0;

        /// <summary>
        /// 4.等待处理的数据
        /// </summary>
        public long WaitProcess
        {
            get
            {
                if (taskDic != null)
                {
                    return taskDic.Sum(p => p.Value.Queuedata.Count);
                }
                return 0;
            }
        }


        /// <summary>
        /// 1.添加总个数
        /// </summary>
        public long PushCount
        {
            get { return pushCount; }
        }

        /// <summary>
        /// 2.处理总个数
        /// </summary>
        public long ProcessingCount
        {
            get { return processingCount; }
        }


        #endregion

    }
    #region 使用池减少内存开消
    /// <summary>
    /// 终端数据入池
    /// </summary>
    public class TerminalMessageRecordPool
    {

        /// <summary>
        /// 默认初始化1000个对像,每个对像最大8KB
        /// </summary>
        public TerminalMessageRecordPool()
        {
            queue.MaxQueue = 500;
            queue.OutOfMaxPrintDelInfo = false;
            for (int i = 0; i < 20; i++)
            {
                queue.Push(new BuffRecord() { Bytes = new byte[1024*8] });
            }
        }

        private BaseQueue<BuffRecord> queue = new BaseQueue<BuffRecord>();


        /// <summary>
        /// 还池
        /// </summary>
        /// <param name="obj"></param>
        public void GaveBack(BuffRecord obj)
        {
            obj.Length = 0;
            queue.Push(obj);
        }

        /// <summary>
        /// 取池
        /// </summary>
        /// <returns></returns>
        public BuffRecord Pop()
        {
            var po = queue.Pop();
            return po == null ? new BuffRecord() { Bytes = new byte[1024*8] } : po;
        }



    }
    /// <summary>
    /// 池对像
    /// </summary>
    public class BuffRecord
    {
        /// <summary>
        /// 字节数
        /// </summary>
        public byte[] Bytes { get; set; }
        /// <summary>
        /// 有效长度
        /// </summary>
        public int Length { get; set; }

    }
    /// <summary>
    /// 实时数据节点,对应的线程对像
    /// </summary>
    public class BuffRecordTask<T>
    {

        /// <summary>
        /// 缓存用队列
        /// </summary>
        internal Queue<T> Queuedata = new Queue<T>(3000);

        /// <summary>
        /// 数据数据对像
        /// </summary>
        public object UserToKen { get; set; }

        /// <summary>
        /// 标识
        /// </summary>
        public string TagName { get; set; }

        /// <summary>
        /// 对应的任务对像
        /// </summary>
        public TaskEx Task { get; set; }

        /// <summary>
        /// 线程标识
        /// </summary>
        public int Splict { get; set; }
    }

    #endregion

}
